package com.example.his.api.mis.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.his.api.common.MinioUtil;
import com.example.his.api.common.PageUtils;
import com.example.his.api.db.dao.GoodsDao;
import com.example.his.api.db.pojo.GoodsEntiy;
import com.example.his.api.exception.HisException;
import com.example.his.api.mis.controller.form.goods.DownloadCheckupExcelForm;
import com.example.his.api.mis.service.GoodsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Service("MisGoodsServiceImpl")
@Slf4j
public class GoodsServiceImpl implements GoodsService {
  
  @Resource
  private GoodsDao goodsDao;
  @Resource
  private MinioUtil minioUtil;
  
  @Override
  public PageUtils searchByPage(Map param) {
    ArrayList <HashMap> list = new ArrayList <>();
    long count = this.searchCount(param);
    if(count > 0) {
      list = goodsDao.searchByPage(param);
    }
    
    int start = (Integer)param.get("start");
    int length = (Integer)param.get("length");
    int pageIndex = start / length + 1;
    PageUtils pageUtils = new PageUtils(list, count, pageIndex, length);
    
    return pageUtils;
  }
  
  @Override
  public long searchCount(Map param) {
    long count = goodsDao.searchCount(param);
    return count;
  }
  
  @Override
  public String uploadImage(MultipartFile file) {
    //    生成新的文件名
    String fileName = IdUtil.simpleUUID() + ".jpg";
    String imagePath = "front/goods/" + fileName;
    minioUtil.uploadImage(imagePath, file);
    return imagePath;
  }
  
  @Override
  @Transactional
  public int insert(GoodsEntiy goodsEntiy) {
    //    计算商品的md5值
    String md5 = this.getEntityMd5(goodsEntiy);
    goodsEntiy.setMd5(md5);
    //    保存商品记录
    int rows = goodsDao.insert(goodsEntiy);
    return rows;
  }
  
  private String getEntityMd5(GoodsEntiy goodsEntiy) {
    JSONObject json = JSONUtil.parseObj(goodsEntiy);
    //    去除下列不属于商品信息的md5值范围
    json.remove("id");
    json.remove("createTime");
    json.remove("updateTime");
    json.remove("status");
    json.remove("salesVolume");
    json.remove("partId");
    json.remove("md5");
    String md5 = MD5.create().digestHex(json.toString()).toUpperCase();
    return md5;
  }
  
  @Override
  public HashMap searchById(int id) {
    Map param = new HashMap() {{
      put("id", id);
    }};
    HashMap map = goodsDao.searchById(param);
    String[] column = { "tag", "checkup_1", "checkup_2", "checkup_3", "checkup_4" };
    for(String item: column) {
      String str = MapUtil.getStr(map, item);
      if(str != null) {
        JSONArray tag = JSONUtil.parseArray(str);
        map.replace(item, tag);
      }
    }
    return map;
  }
  
  @Override
  @Transactional
  @CacheEvict(cacheNames = "goods", key = "#goodsEntiy.id")
  public int update(GoodsEntiy goodsEntiy) {
    //    修改商品需要重新计算MD5值
    String md5 = this.getEntityMd5(goodsEntiy);
    goodsEntiy.setMd5(md5);
    int rows = goodsDao.update(goodsEntiy);
    return rows;
  }
  
  //  上传Excel文件，更新checkup字段
  @Override
  @Transactional
  @CacheEvict(cacheNames = "goods", key = "#id")
  public void updateCheckup(int id, MultipartFile file) {
    //    创建空的arraylist保存从excel文档解析出来的数据
    ArrayList list = new ArrayList();
    
    //    读取文件内容
    try(InputStream in = file.getInputStream(); BufferedInputStream bin = new BufferedInputStream(in);) {
      XSSFWorkbook workbook = new XSSFWorkbook(bin);
      //      获Excel文档的第一个sheet页
      XSSFSheet sheet = workbook.getSheetAt(0);
      for(int i = 1; i <= sheet.getLastRowNum(); i++) {
        XSSFRow row = sheet.getRow(i);
        
        //        获取检查地点
        XSSFCell cell_1 = row.getCell(0);
        String value_1 = cell_1.getStringCellValue();
        
        //        获取导诊名称
        XSSFCell cell_2 = row.getCell(1);
        String value_2 = cell_2.getStringCellValue();
        
        //        获取检查项
        XSSFCell cell_3 = row.getCell(2);
        String value_3 = cell_3.getStringCellValue();
        
        //        获取采集方式
        XSSFCell cell_4 = row.getCell(3);
        String value_4 = cell_4.getStringCellValue();
        
        
        //        获取模板编码
        XSSFCell cell_5 = row.getCell(4);
        String value_5 = cell_5.getStringCellValue();
        
        //        获取性别要求
        XSSFCell cell_6 = row.getCell(5);
        String value_6 = cell_6.getStringCellValue();
        
        //        获取模板值
        XSSFCell cell_7 = row.getCell(6);
        String value_7 = cell_7.getStringCellValue();
        
        //        获取输出模板
        XSSFCell cell_8 = row.getCell(7);
        String value_8 = cell_8.getStringCellValue();
        
        //        使用map对象按照添加顺序保存键值对
        LinkedHashMap map = new LinkedHashMap() {{
          put("place", value_1);
          put("name", value_2);
          put("item", value_3);
          put("type", value_4);
          put("code", value_5);
          put("sex", value_6);
          put("value", value_7);
          put("template", value_8);
        }};
        //        把当前行解释出来的数据保存到arraylist中
        list.add(map);
      }
      System.out.println(list);
      
    } catch(Exception e) {
      throw new HisException("处理Excel文件失败", e);
    }
    
    if(list.size() == 0) {
      throw new HisException("Excel文件为空");
    }
    
    //    把文件存储到minio服务器上
    String path = "/mis/goods/checkup/" + id + ".xlsx";
    minioUtil.uploadExcel(path, file);
    
    //    根据商品id查询商品记录，然后重新计算md5值，更新商品的checkup和md5字段
    GoodsEntiy entiy = goodsDao.searchEntityById(id);
    String checkup = JSONUtil.parseArray(list).toString();
    entiy.setCheckup(checkup);
    String md5 = this.getEntityMd5(entiy);
    HashMap param = new HashMap() {{
      put("id", id);
      put("checkup", checkup);
      put("md5", md5);
    }};
    //    保存数据
    int rows = goodsDao.updateCheckup(param);
    if(rows != 1) {
      throw new HisException("跟新体检内容失败");
    }
    
  }
  
  @Override
  @Transactional
  @CacheEvict(cacheNames = "goods", key = "#param.get('id')")
  public boolean updateStatus(Map param) {
    int rows = goodsDao.updateStatus(param);
    boolean b = rows == 1;
    return b;
  }
  
  //  根据ids删除商品
  @Override
  @Transactional
  @CacheEvict(cacheNames = "goods", key = "#ids")
  public int deleteByIds(Integer[] ids) {
    //    删除商品前先查询商品封面
    ArrayList <String> imageList = goodsDao.searchImageByIds(ids);
    int rows = goodsDao.deleteByIds(ids);
    if(rows > 0) {
      //       成功删除了商品，删除商品封面
      for(String path: imageList) {
        minioUtil.deleteFile(path);
      }
    }
    return rows;
  }
}
